//
// Created by Criinal Nicole on 2020/6/15.
//

#include <cstring>
#include <iostream>
#include "SuperNode.h"
#include "FileIndexNode.h"
#include "../Controller/Controller.h"
#include <cmath>

using std::cout;
using std::endl;


typeof(SUPER_NODE::SuperNode) SUPER_NODE::SuperNode;

//初始化，
void SUPER_NODE::init() {
    auto &sn = SuperNode;
//    成组块链接法分配磁盘块
    sn._blockStackSize = BLOCK::BLOCK_SIZE_INT;
    for (int i = 0; i < BLOCK::BLOCK_SIZE_INT; ++i) {
        sn._blockStack[i] = i;
    }
    sn._nextBlockStack = BLOCK::BLOCK_SIZE_INT;
    sn._curInode = 1;
    sn._nextInode = 2;
}

int SUPER_NODE::iAlloc() {
    if (SuperNode._blockStackSize > 0) {
        SuperNode._blockStackSize--;
        return SuperNode._blockStack[SuperNode._blockStackSize];
    } else {
        int ret = SuperNode._nextBlockStack;
        if (ret < 0)return -1;
        SuperNode._blockStackSize = BLOCK::blocks[ret]._blockStackSizeInt;
        for (int i = 0; i < BLOCK::blocks[ret]._blockStackSizeInt; ++i) {
            SuperNode._blockStack[i] = BLOCK::blocks[ret]._blockStack[i];
        }
        SuperNode._nextBlockStack = BLOCK::blocks[ret]._nextBlockStack;
        return ret;
    }


}

void SUPER_NODE::outPut(int tmp) {
    if (FILE_INDEX_NODE::fileIndexNodes[tmp]._posInDictionaryBlock == -1) {
        auto *node = &FILE_INDEX_NODE::fileIndexNodes[tmp];
        if (node->_iLarge) {
            for (int i = 0; i < node->_blockNum - 1; ++i) {
                char *b = (char *) BLOCK::blocks[node->_blockId[i]]._blockStack;
                for (int j = 0; j < BLOCK::blocks[node->_blockId[i]]._blockStackSizeChar; ++j) {
                    cout << b[j];
                }
            }
//                大文件
            int next = node->_blockId[node->_blockNum - 1];
            SUPER_NODE::outPut(next);
        } else {
            for (int i = 0; i < node->_blockNum; ++i) {
                char *b = (char *) BLOCK::blocks[node->_blockId[i]]._blockStack;
                for (int j = 0; j < BLOCK::blocks[node->_blockId[i]]._blockStackSizeChar; ++j) {
                    cout << b[j];
                }
            }
        }
    } else {
        cout << "Not a file.";
    }
}

void SUPER_NODE::iFree(int blockId) {
    if (SuperNode._blockStackSize == BLOCK::BLOCK_SIZE_INT) {
        for (int i = 0; i < BLOCK::BLOCK_SIZE_INT; ++i) {
            BLOCK::blocks[blockId]._blockStack[i] = SuperNode._blockStack[i];
        }
        BLOCK::blocks[blockId]._nextBlockStack = SuperNode._nextBlockStack;
        SuperNode._nextBlockStack = blockId;
        SuperNode._blockStackSize = 0;
    } else {
        SuperNode._blockStack[SuperNode._blockStackSize++] = blockId;
    }
}

int SUPER_NODE::iGet() {
    if (SuperNode._curInode != -1) {
        int tmp = SuperNode._curInode;
        FILE_INDEX_NODE::fileIndexNodes[tmp]._iAlloc = 1;
        SuperNode._curInode = SuperNode._nextInode;
        if (SuperNode._curInode != -1)
            SuperNode._nextInode = FILE_INDEX_NODE::fileIndexNodes[SuperNode._curInode]._nextInode;
        return tmp;
    } else {
        return -1;
    }
}

void SUPER_NODE::iPut(int iNodeId) {
    auto &iNode = FILE_INDEX_NODE::fileIndexNodes[iNodeId];
//    判断iNode的nextInode是否为正，为-1则为文件，否则为目录
    if (iNode._posInDictionaryBlock == -1) {
//        文件，回收底下所有的block
        if (iNode._iLarge) {
//            采用间址法
            for (int i = 0; i < iNode._blockNum - 1; ++i) {
                iFree(iNode._blockId[i]);
            }
            iPut(iNode._blockId[iNode._blockNum - 1]);
        } else {
            for (int i = 0; i < iNode._blockNum; ++i) {
                iFree(iNode._blockId[i]);
            }
        }
    } else {
//        目录, 不管是不是间址存储，都为iNode点的释放
        for (int i = 0; i < iNode._blockNum; ++i) {
            iPut(iNode._blockId[i]);
        }
    }
    iNode._iAlloc = 0;
    iNode._posInDictionaryBlock = -1;
    iNode._nextInode = SuperNode._curInode;
    SuperNode._curInode = iNodeId;
}

int SUPER_NODE::nameI(char *filePath) {
    auto len = strlen(filePath);
    if (len <= 0)return -1;
    if (filePath[0] == '/') {
//        绝对路径
        return nameI(0, ++filePath);
    } else {
        return nameI(Controller::curDictionaryInode, filePath);
    }
}

int SUPER_NODE::nameI(int iNodeId, char *fileName) {
    if (strlen(fileName) == 0)
        return iNodeId;
    char _fileName[FILE_INDEX_NODE::MAX_NAME_SIZE];

    int len = 0;
    char *tmpFileName = fileName;
    while ((*fileName) != '\0' && (*fileName) != '/') {
        _fileName[len++] = *fileName;
        fileName++;
    }
    _fileName[len] = 0;
    if (*fileName == '\0') {
//        到尾巴了，不需要继续递归
        auto &iNode = FILE_INDEX_NODE::fileIndexNodes[iNodeId];
        if (iNode._iLarge) {
//            大目录
            for (int i = 0; i < iNode._blockNum - 1; ++i) {
                auto &sonNode = FILE_INDEX_NODE::fileIndexNodes[iNode._blockId[i]];
                if (!sonNode._iAlloc)continue;
                if (!strcmp(sonNode._Name, tmpFileName)) {
                    return iNode._blockId[i];
                }
            }
            return nameI(iNode._blockId[iNode._blockNum - 1], tmpFileName);
        } else {
            for (int i = 0; i < iNode._blockNum; ++i) {
                auto &sonNode = FILE_INDEX_NODE::fileIndexNodes[iNode._blockId[i]];
                if (!sonNode._iAlloc)continue;
                if (!strcmp(sonNode._Name, tmpFileName)) {
                    return iNode._blockId[i];
                }
            }
            return -1;
        }
    } else {
        fileName++;
//        需要继续递归
        auto &iNode = FILE_INDEX_NODE::fileIndexNodes[iNodeId];
        if (iNode._iLarge) {
//            大目录
            for (int i = 0; i < iNode._blockNum - 1; ++i) {
                auto &sonNode = FILE_INDEX_NODE::fileIndexNodes[iNode._blockId[i]];
                if (!sonNode._iAlloc)continue;
                if (!strcmp(sonNode._Name, _fileName)) {
                    return nameI(iNode._blockId[i], fileName);
                }
            }
            return nameI(iNode._blockId[iNode._blockNum - 1], tmpFileName);
        } else {
            for (int i = 0; i < iNode._blockNum; ++i) {
                auto &sonNode = FILE_INDEX_NODE::fileIndexNodes[iNode._blockId[i]];
                if (!sonNode._iAlloc)continue;
                if (!strcmp(sonNode._Name, _fileName)) {
                    return nameI(iNode._blockId[i], fileName);
                }
            }
            return -1;
        }
    }
}

void SUPER_NODE::cd(char *filePath) {
    int tmp = nameI(filePath);
    if (tmp != -1) {
        if (FILE_INDEX_NODE::fileIndexNodes[tmp]._posInDictionaryBlock == -1) {
            cout << "\"" << filePath << "\" is not a directory.";
        } else {
            Controller::curDictionaryInode = tmp;
        }
    } else {
        cout << "Invalid Path!" << endl;
    }
}

void SUPER_NODE::addDictionary(char *dictionaryName) {
    if (nameI(Controller::curDictionaryInode, dictionaryName) != -1) {
        cout << "已有文件\n";
        return;
    }
//    申请inode
    int newINodeNum = getNewInode();
    if (newINodeNum == -1) {
        return;
    }

    auto &newINode = FILE_INDEX_NODE::fileIndexNodes[newINodeNum];
    strcpy(newINode._Name, dictionaryName);
    newINode._iAlloc = 1;
    newINode._posInDictionaryBlock = FILE_INDEX_NODE::MAX_FILE_INDEX_NUM;
    FILE_INDEX_NODE::fileIndexNodes[Controller::lastINodeNum]._posInDictionaryBlock = newINodeNum;
    Controller::lastINodeNum = newINodeNum;

//    获取当前目录的i节点
    FILE_INDEX_NODE::FileIndexNode *node
            = &FILE_INDEX_NODE::fileIndexNodes[Controller::curDictionaryInode];
    if (node->_iLarge) {
        while (node->_iLarge) {
            node = &FILE_INDEX_NODE::fileIndexNodes[node->_blockId[BLOCK::BLOCK_SIZE_INT - 1]];
        }
    }
    auto &iNode = *node;
    addNewInode(iNode, newINodeNum);

    Controller::store();
}

void SUPER_NODE::addFile(char *fileName, char *fileContent) {
    if (nameI(Controller::curDictionaryInode, fileName) != -1) {
        cout << "已有文件\n";
        return;
    }
    auto inodeNum = getNewInode();
    if (inodeNum == -1) {
        cout << "i节点不足\n";
        return;
    }
    auto &iNode = FILE_INDEX_NODE::fileIndexNodes[inodeNum];
    auto &father = FILE_INDEX_NODE::fileIndexNodes[Controller::curDictionaryInode];

    addNewInode(father, inodeNum);
    strcpy(iNode._Name, fileName);
    iNode._userId = Controller::curUserId;
    iNode._ownerPri = 7;
    iNode._othersPri = 0;
    iNode._posInDictionaryBlock = -1;
    auto len = strlen(fileContent);
    int blockNum = ceil(1.0 * len / BLOCK::BLOCK_SIZE_CHAR);
    if (blockNum <= BLOCK::BLOCK_SIZE_INT) {
        for (int i = 0; i < blockNum; ++i) {
            int p = iAlloc();
            if (p == -1) {
                cout << "空间不足\n";
                return;
            }
            iNode._blockId[iNode._blockNum++] = p;
            char *blockContent = (char *) BLOCK::blocks[p]._blockStack;
            for (int j = 0; j < BLOCK::BLOCK_SIZE_CHAR; ++j) {
                if (i * BLOCK::BLOCK_SIZE_CHAR + j >= len) {
                    blockContent[j] = 0;
                    BLOCK::blocks[p]._blockStackSizeChar = j;
                    break;
                }
                blockContent[j] = fileContent[i * BLOCK::BLOCK_SIZE_CHAR + j];
                BLOCK::blocks[i]._blockStackSizeChar = j + 1;
            }
        }
        iNode._blockNum = blockNum;
    } else {
        auto *curNode = &iNode;
        for (int i = 0; i <= blockNum; i += BLOCK::BLOCK_SIZE_INT - 1) {
//            i+k:块的序号
            for (int k = 0; k < BLOCK::BLOCK_SIZE_INT - 1; ++k) {
                if (i + k > blockNum)return;
                int p = iAlloc();
                if (p == -1) {
                    cout << "空间不足\n";
                    return;
                }
                char *blockContent = (char *) BLOCK::blocks[p]._blockStack;
                for (int j = 0; j < BLOCK::BLOCK_SIZE_CHAR; ++j) {
                    if ((i + k) * BLOCK::BLOCK_SIZE_CHAR + j >= len) {
                        blockContent[j] = 0;
                        BLOCK::blocks[p]._blockStackSizeChar = j;
                        break;
                    }
                    int q = (i + k) * BLOCK::BLOCK_SIZE_CHAR + j;
                    blockContent[j] = fileContent[q];
                    BLOCK::blocks[p]._blockStackSizeChar = j + 1;
                }
                curNode->_blockId[curNode->_blockNum] = p;
                curNode->_blockNum = k + 1;
            }

            int iN = getNewInode();
            if (iN == -1)return;
            auto &ii = FILE_INDEX_NODE::fileIndexNodes[iN];
            ii._iAlloc = 1;
            curNode->_iLarge = 1;
            curNode->_blockId[curNode->_blockNum] = iN;
            curNode->_blockNum++;

            ii._posInDictionaryBlock = -1;
            curNode = &FILE_INDEX_NODE::fileIndexNodes[iN];
        }
    }
}

void SUPER_NODE::addNewInode(FILE_INDEX_NODE::FileIndexNode &iNode, int newINodeNum) {

    auto &newINode = FILE_INDEX_NODE::fileIndexNodes[newINodeNum];

    if (iNode._blockNum == BLOCK::BLOCK_SIZE_INT) {
        int tmpNum = getNewInode();
        if (tmpNum == -1)
            return;
        auto &tmp = FILE_INDEX_NODE::fileIndexNodes[tmpNum];
        tmp._blockNum = 2;
        tmp._blockId[0] = iNode._blockId[BLOCK::BLOCK_SIZE_INT - 1];
        tmp._blockId[1] = newINodeNum;
        iNode._blockId[BLOCK::BLOCK_SIZE_INT - 1] = tmpNum;
        iNode._iLarge = 1;
        tmp._iAlloc = 1;
        tmp._posInDictionaryBlock = FILE_INDEX_NODE::MAX_FILE_INDEX_NUM;
        FILE_INDEX_NODE::fileIndexNodes[Controller::lastINodeNum]._posInDictionaryBlock = tmpNum;
        Controller::lastINodeNum = tmpNum;
    } else {
        iNode._iLarge = 0;
        iNode._blockId[iNode._blockNum++] = newINodeNum;
    }
}

int SUPER_NODE::getNewInode() {
    int tmpNum = iGet();
    if (tmpNum == -1) {
        cout << "No iNode left!\n";
        return -1;
    }
    auto &tmp = FILE_INDEX_NODE::fileIndexNodes[tmpNum];
    memset(tmp._Name, 0, sizeof(tmp._Name));
    tmp._userId = Controller::curUserId;
    tmp._ownerPri = 7;
    tmp._othersPri = 0;
    tmp._iAlloc = 1;
    return tmpNum;
}

int SUPER_NODE::checkPrivilege() {
    int &nodeId = Controller::curDictionaryInode;
    if (!Controller::curUserId)
        return 7;
    auto tmp = FILE_INDEX_NODE::fileIndexNodes[nodeId];

    if (Controller::curUserId == tmp._userId) {
        return tmp._ownerPri;
    }
    return tmp._othersPri;
}

void SUPER_NODE::deleteFile() {
    using Controller::curDictionaryInode;
    if (curDictionaryInode == 0) {
        cout << "Warning: Delete root directory!\n";
        SUPER_NODE::init();
        DIRECTORY_BLOCK::init();
        FILE_INDEX_NODE::init();
        BLOCK::init();
        Controller::store();
        Controller::lastINodeNum = 0;
        Controller::store();
        return;
    }
    iPut(curDictionaryInode);
    Controller::lastINodeNum = 0;
    Controller::getLastINodeNum(0);
    curDictionaryInode = 0;
    Controller::store();
}

void SUPER_NODE::openFile(char *filePath) {
    int tmp = nameI(filePath);
    if (tmp != -1) {
        SUPER_NODE::outPut(tmp);
    } else {
        cout << "Invalid Path!" << endl;
    }
}

void SUPER_NODE::changePrivilege(int priv) {
    if (Controller::curUserId != 0) {
        cout << "Only admin can change privilege\n";
        return;
    }
    if (priv > 7) {
        cout << "Invalid privilege\n";
        return;
    }
    int &nodeId = Controller::curDictionaryInode;
    auto tmp = FILE_INDEX_NODE::fileIndexNodes[nodeId];

    if (Controller::curUserId == tmp._userId) {
        tmp._ownerPri = priv;
        return;
    }
    tmp._othersPri = priv;
}

void SUPER_NODE::ls(int iNodeNum) {
    auto *iNode = &FILE_INDEX_NODE::fileIndexNodes[iNodeNum];
    if (iNode->_iLarge) {
        for (int i = 0; i < iNode->_blockNum - 1; ++i) {
            cout << FILE_INDEX_NODE::fileIndexNodes[iNode->_blockId[i]]._Name << " ";
        }
        ls(iNode->_blockId[iNode->_blockNum - 1]);
    } else {
        for (int i = 0; i < iNode->_blockNum; ++i) {
            cout << FILE_INDEX_NODE::fileIndexNodes[iNode->_blockId[i]]._Name << " ";
        }
    }

}

void SUPER_NODE::ls() {
    ls(Controller::curDictionaryInode);
}



